package com.gcloud.mesh.dcs.service;

import com.gcloud.framework.db.PageResult;
import com.gcloud.mesh.asset.dao.IaasDao;
import com.gcloud.mesh.asset.dao.NodeDao;
import com.gcloud.mesh.asset.entity.IaasEntity;
import com.gcloud.mesh.asset.entity.NodeEntity;
import com.gcloud.mesh.dcs.dao.VoltageFmDao;
import com.gcloud.mesh.dcs.entity.VoltageFmEntity;
import com.gcloud.mesh.dcs.enums.ControlType;
import com.gcloud.mesh.dcs.rpc.RPCClient;
import com.gcloud.mesh.header.enums.VoltageFmStrategy;
import com.gcloud.mesh.header.exception.BaseException;
import com.gcloud.mesh.header.msg.agent.SetDvfsMsg;
import com.gcloud.mesh.header.msg.dcs.DetailDvfsMsg;
import com.gcloud.mesh.header.msg.dcs.PageVoltageFmMsg;
import com.gcloud.mesh.header.msg.dcs.SetVoltageFmStrategyMsg;
import com.gcloud.mesh.header.msg.dvfs.ReportDvfsMsg;
import com.gcloud.mesh.header.vo.asset.NodeItemVo;
import com.gcloud.mesh.header.vo.dcs.DetailDvfsVo;
import com.gcloud.mesh.header.vo.dcs.VoltageFmDbVo;
import com.gcloud.mesh.header.vo.dcs.VoltageFmVo;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.exception.ParamException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class VoltageFmService {

    @Autowired
    private VoltageFmDao voltageFmDao;

    @Autowired
    private NodeDao nodeDao;

    @Autowired
    private IaasDao iaasDao;

    @Autowired
    private RPCClient rpcClient;

    public PageResult<VoltageFmVo> page(PageVoltageFmMsg msg) {
        PageResult<VoltageFmDbVo> pageResult = voltageFmDao.getPage(msg.getPageNo(), msg.getPageSize(), msg.getFactorName(), msg.getDatacenterId(), VoltageFmDbVo.class);
        PageResult<VoltageFmVo> result = new PageResult<>();
        List<VoltageFmVo> list = new ArrayList<>();
        for (VoltageFmDbVo dbVo : pageResult.getList()) {
            VoltageFmVo vo = new VoltageFmVo();
            BeanUtils.copyProperties(dbVo, vo);
            String supportStrategies = dbVo.getSupportStrategies();
            if (!ObjectUtils.isEmpty(supportStrategies)) {
                vo.setSupportStrategies(Arrays.asList(supportStrategies.split("\\|")));
            }
            list.add(vo);
        }
        result.setList(list);
        result.setPageNo(pageResult.getPageNo());
        result.setPageSize(pageResult.getPageSize());
        result.setTotalCount(pageResult.getTotalCount());
        return result;
    }


    public void setFmStrategy(SetVoltageFmStrategyMsg msg) {
        IaasEntity iaasEntity = iaasDao.getById(msg.getId());
        if (iaasEntity == null) {
            log.error("[{}][Dvfs]更新设备失败,设备不存在", msg.getId());
            throw new ParamException("设备不存在");
        }
        NodeEntity nodeEntity = nodeDao.getById(iaasEntity.getDeviceId());
        if (nodeEntity == null) {
            log.error("[{}][Dvfs]更新设备失败,设备对应的ipmi不存在", iaasEntity.getDeviceId());
            throw new BaseException("设备对应的ipmi不存在");
        }
        VoltageFmEntity voltageFmEntity = voltageFmDao.findOneByProperty("resource_id", msg.getId());
        if (voltageFmEntity == null) {
            log.error("[{}][Dvfs]更新设备失败,设备对应的dfvs不存在", msg.getId());
            throw new BaseException("设备对应的dvfs不存在");
        }
        List<String> fields = new ArrayList<>();
        //如果需要设置控制方式
        if (msg.getControlType() != null) {
            ControlType.checkAndGet(msg.getControlType());
            voltageFmEntity.setControlType(msg.getControlType());
            fields.add("control_type");
        }
        //如果需要设置策略
        if (msg.getControlType() == null || Objects.equals(ControlType.MANUAL.getNo(), msg.getControlType())) {
            if (StringUtils.isEmpty(msg.getVoltageFmStrategy())) {
                log.error("[{}][Dvfs]策略不能为空", msg.getVoltageFmStrategy());
                throw new BaseException("策略不能为空");
            }
            VoltageFmStrategy.getAndCheck(msg.getVoltageFmStrategy());
            if (Objects.equals(msg.getVoltageFmStrategy(), VoltageFmStrategy.USERSPACE.name()) && ObjectUtils.isEmpty(msg.getUserFrequency())) {
                log.error("[{}][Dvfs]设置userspace策略时，自定义频率不能为空", msg.getUserFrequency());
                throw new BaseException("设置userspace策略时，自定义频率不能为空");
            }
            if (ObjectUtils.isEmpty(voltageFmEntity.getSupportStrategies())
                    || !Arrays.asList(voltageFmEntity.getSupportStrategies().split("\\|")).contains(msg.getVoltageFmStrategy())) {
                log.error("[{}][Dvfs]更新设备失败,设备不支持该策略", msg.getVoltageFmStrategy());
                throw new BaseException("策略不支持");
            }
            voltageFmEntity.setVoltageFmStrategy(msg.getVoltageFmStrategy());
            voltageFmEntity.setFrequency(msg.getUserFrequency() == null ? 0F : msg.getUserFrequency());
            fields.add("voltage_fm_strategy");
            fields.add("frequency");
        }
        //如果为自动，设置为默认调度方式
        if (Objects.equals(ControlType.AUTO.getNo(), msg.getControlType())) {
            if (ObjectUtils.isEmpty(voltageFmEntity.getSupportStrategies())) {
                log.error("[{}][Dvfs]不支持调度策略", voltageFmEntity.getSupportStrategies());
                throw new BaseException("不支持调度策略");
            }
            fields.add("voltage_fm_strategy");
            voltageFmEntity.setVoltageFmStrategy(VoltageFmStrategy.POWERSAVE.name());

        }
        //去除ping带外ip
        //checkConnect(nodeEntity.getIpmiIp());

        //更新dvfs
        voltageFmDao.update(voltageFmEntity, fields);

        //向server发送设置dvfs的请求
        SetDvfsMsg sendMsg = new SetDvfsMsg();
        sendMsg.setStrategy(voltageFmEntity.getVoltageFmStrategy());
        sendMsg.setFrequency(msg.getUserFrequency());
        sendMsg.setNodeId(iaasEntity.getEsn());
        rpcClient.setDvfs(sendMsg, nodeEntity.getIpmiIp());

    }

/*	public void checkConnect(String ip){
		HttpUtil.checkPing(ip);
	}*/

    public DetailDvfsVo detailDvfs(DetailDvfsMsg msg) {
        VoltageFmEntity entity = voltageFmDao.findOneByProperty("resource_id", msg.getId());
        if (entity == null) {
            throw new ParamException(null, "设备对应的电压调频不存在");
        }
        DetailDvfsVo vo = new DetailDvfsVo();
        vo.setResourceId(msg.getId());
        if (!ObjectUtils.isEmpty(entity.getSupportStrategies())) {
            vo.setSupportStrategies(Arrays.asList(entity.getSupportStrategies().split("\\|")));
        }
        vo.setControlType(entity.getControlType());
        return vo;
    }

    /**
     * 用于手动同步dvfs
     */
    public void syncDvfsByService() {
        List<NodeItemVo> nodeItems = iaasDao.listNode(null, null, NodeItemVo.class);
        for (NodeItemVo nodeItem : nodeItems) {
            rpcClient.syncDvfs(nodeItem.getMgmIp());
        }
    }

    /**
     * 用于server同步数据，server调用
     *
     * @param msg
     */
    public void syncDvfsByServer(ReportDvfsMsg msg) {
        List<NodeItemVo> nodeItems = iaasDao.listNode(null, null, NodeItemVo.class)
                .stream()
                .filter(node -> Objects.equals(node.getHostname(), msg.getHostname()))
                .collect(Collectors.toList());
        if (nodeItems.size() != 1) {
            log.info("[VoltageFmService]数据库中不存在或者存在多个hostname为:{}的服务器", msg.getHostname());
            return;
        }
        // hostname是唯一
        NodeItemVo nodeItem = nodeItems.get(0);
        log.info("[VoltageFmService]正在同步hostname为:{}的服务器的dvfs", nodeItem.getHostname());
        VoltageFmEntity voltageFm = voltageFmDao.findOneByProperty("resource_id", nodeItem.getId());
        //如果数据库中不存在,则新增
        if (voltageFm == null) {
            voltageFm = new VoltageFmEntity();
            voltageFm.setId(UUID.randomUUID().toString());
            voltageFm.setResourceId(nodeItem.getId());
            voltageFm.setVoltageFmStrategy(msg.getCurrentStrategy());
            voltageFm.setFrequency(msg.getCurrentFrequency());
            voltageFm.setSupportStrategies(msg.getAvailableStrategy());
            voltageFm.setControlType(ControlType.AUTO.getNo());
            voltageFm.setRatedPower(nodeItem.getRatedPower());
            voltageFm.setPowerConsumption(nodeItem.getPowerConsumption());
            voltageFmDao.save(voltageFm);
        } else {
            List<String> fields = Arrays.asList("rated_power", "power_consumption", "frequency", "voltage_fm_strategy", "support_strategies");
            voltageFm.setRatedPower(nodeItem.getRatedPower());
            voltageFm.setPowerConsumption(nodeItem.getPowerConsumption());
            voltageFm.setFrequency(msg.getCurrentFrequency());
            voltageFm.setVoltageFmStrategy(msg.getCurrentStrategy());
            voltageFm.setSupportStrategies(msg.getAvailableStrategy());
            voltageFmDao.update(voltageFm, fields);
        }

    }
}
